import datetime as dt
import matplotlib.pyplot as plt
from pandas_datareader import data as web
import pandas as pd
# Import and clean data
tickers = ['NIO', 'WKHS', 'CRSR', 'IWDA.AS']
stock_names = ['NIO', 'WorkHorse', 'Corsair', 'iShares World']
shares = [6, 8, 8, 19]
prices = []
total = []
for ticker in tickers:
df = web.DataReader(ticker, 'yahoo', dt.datetime(2019,8,10), dt.datetime.now())
price = df[-1:]['Close'][0]
prices.append(price)
index = prices.index(price)
total.append(price * shares[index])
stocks_tickers = ['NIO', 'WKHS', 'CRSR', 'IWDA.AS', 'SXR8.DE']
stocks = web.DataReader(stocks_tickers, 'yahoo', dt.datetime(2019,8,10), dt.datetime.now())
total_str = ['$'+str(round(t,2)) for t in total]
stock_names_and_total = stock_names.copy()
stock_names_and_total.append('Total')
total_portfolio = total.copy()
total_portfolio.append(sum(total))
total_portfolio_str = ['$'+str(round(t,2)) for t in total_portfolio]
stocks.drop(columns=['Adj Close','High','Low','Open','Volume'], inplace=True)
stocks_close = stocks.Close.reset_index().copy()
# Current Portfolio value
current_portfolio = sum(total)
# stocks_tickers = ['NIO', 'WKHS', 'CRSR', 'IWDA.AS', 'SXR8.DE']
avg_price = [31.65, 21.5, 37.9, 55.0842]
shares = [6, 8, 8, 19]
initial_purchase = [shares[i]*avg_price[i] for i in range(len(avg_price))]
initial_portfolio = sum(initial_purchase)
initial_purchase_str = ['$'+str(round(t)) for t in initial_purchase]
# Current Weights in My Portfolio
weights = [price/initial_portfolio for price in initial_purchase]
# Calculating Return
todays_price = list(stocks_close[-1:][tickers].values.flatten())
returns = [todays_price[i]/avg_price[i]-1 for i in range(len(avg_price))]
# Portfolio Total Return
total_return = sum([returns[i]*weights[i] for i in range(len(returns))])
total_mkt_ret = 254
myportfolio = pd.DataFrame({'Stocks': stock_names,'Tickers': tickers, '# Shares': shares,
'Weights': weights, 'Returns': returns, 'Price Today': todays_price,
'Initial Purchase Price': avg_price, 'Initial Purchase per Stock': initial_purchase,
'Current Value': total})
myportfolio
Stocks | Tickers | # Shares | Weights | Returns | Price Today | Initial Purchase Price | Initial Purchase per Stock | Current Value | |
---|---|---|---|---|---|---|---|---|---|
0 | NIO | NIO | 6 | 0.110942 | 0.846445 | 58.439999 | 31.6500 | 189.9000 | 350.639992 |
1 | WorkHorse | WKHS | 8 | 0.100485 | 0.105116 | 23.760000 | 21.5000 | 172.0000 | 190.080002 |
2 | Corsair | CRSR | 8 | 0.177134 | -0.004486 | 37.730000 | 37.9000 | 303.2000 | 301.839996 |
3 | iShares World | IWDA.AS | 19 | 0.611439 | 0.112297 | 61.270000 | 55.0842 | 1046.5998 | 1164.130009 |
stocks_close['My Portfolio'] = (stocks_close['NIO']*shares[0]+stocks_close['WKHS']*shares[1]+stocks_close['CRSR']*shares[2]+
stocks_close['IWDA.AS']*shares[3])
stocks_close_dropna = stocks_close.dropna().copy()
stocks_close_dropna
Symbols | Date | NIO | WKHS | CRSR | IWDA.AS | SXR8.DE | My Portfolio |
---|---|---|---|---|---|---|---|
287 | 2020-09-23 | 17.959999 | 22.469999 | 14.250000 | 54.235001 | 283.760010 | 1431.985001 |
288 | 2020-09-24 | 17.850000 | 22.129999 | 15.580000 | 53.619999 | 280.279999 | 1427.559975 |
289 | 2020-09-25 | 18.320000 | 24.809999 | 17.250000 | 54.000000 | 282.720001 | 1472.399994 |
291 | 2020-09-29 | 20.850000 | 27.100000 | 18.780001 | 54.639999 | 286.239990 | 1530.299999 |
292 | 2020-09-30 | 21.219999 | 25.280001 | 20.100000 | 54.959999 | 289.260010 | 1534.599987 |
293 | 2020-10-01 | 21.760000 | 25.080000 | 20.950001 | 55.084999 | 289.679993 | 1545.414989 |
294 | 2020-10-02 | 21.180000 | 23.620001 | 20.900000 | 54.889999 | 287.829987 | 1526.149994 |
299 | 2020-10-09 | 21.469999 | 26.770000 | 18.110001 | 56.195000 | 295.140015 | 1555.564999 |
304 | 2020-10-16 | 28.480000 | 22.809999 | 19.200001 | 56.825001 | 300.700012 | 1586.635014 |
309 | 2020-10-23 | 27.160000 | 20.340000 | 24.670000 | 55.650002 | 293.459991 | 1580.390030 |
314 | 2020-10-30 | 30.580000 | 15.380000 | 24.040001 | 53.514999 | 281.989990 | 1515.624996 |
319 | 2020-11-06 | 41.630001 | 17.290001 | 27.080000 | 56.505001 | 297.250000 | 1678.335033 |
324 | 2020-11-13 | 44.560001 | 19.219999 | 29.180000 | 57.970001 | 303.440002 | 1755.990028 |
329 | 2020-11-20 | 49.250000 | 25.780001 | 40.330002 | 58.529999 | 304.190002 | 1936.449997 |
333 | 2020-11-27 | 54.000000 | 27.180000 | 38.770000 | 59.209999 | 306.730011 | 1976.589989 |
338 | 2020-12-04 | 43.040001 | 22.070000 | 35.680000 | 59.154999 | 306.720001 | 1844.184982 |
343 | 2020-12-11 | 41.980000 | 21.780001 | 33.259998 | 58.730000 | 303.399994 | 1808.069981 |
348 | 2020-12-18 | 46.720001 | 21.150000 | 38.700001 | 59.285000 | 305.079987 | 1885.535007 |
357 | 2021-01-04 | 53.490002 | 21.420000 | 34.750000 | 59.305000 | 304.350006 | 1897.095016 |
358 | 2021-01-05 | 53.200001 | 22.430000 | 35.900002 | 59.419998 | 305.070007 | 1914.819984 |
359 | 2021-01-06 | 50.500000 | 23.650000 | 37.889999 | 60.270000 | 309.769989 | 1940.450001 |
360 | 2021-01-07 | 54.279999 | 27.600000 | 39.430000 | 60.799999 | 312.799988 | 2017.119984 |
361 | 2021-01-08 | 58.919998 | 25.565001 | 38.310001 | 61.099998 | 314.010010 | 2025.419975 |
366 | 2021-01-15 | 56.270000 | 23.340000 | 38.130001 | 61.259998 | 315.200012 | 1993.319981 |
367 | 2021-01-19 | 58.439999 | 23.760000 | 37.730000 | 61.270000 | 315.200012 | 2006.689999 |
stocks_close_dropna['Portfolio Return'] = stocks_close_dropna['My Portfolio'] / stocks_close_dropna['My Portfolio'].shift(1) - 1
stocks_close_dropna['Market Return'] = stocks_close_dropna['SXR8.DE'] / stocks_close_dropna['SXR8.DE'].shift(1) - 1
stocks_close_dropna
Symbols | Date | NIO | WKHS | CRSR | IWDA.AS | SXR8.DE | My Portfolio | Portfolio Return | Market Return |
---|---|---|---|---|---|---|---|---|---|
287 | 2020-09-23 | 17.959999 | 22.469999 | 14.250000 | 54.235001 | 283.760010 | 1431.985001 | NaN | NaN |
288 | 2020-09-24 | 17.850000 | 22.129999 | 15.580000 | 53.619999 | 280.279999 | 1427.559975 | -0.003090 | -0.012264 |
289 | 2020-09-25 | 18.320000 | 24.809999 | 17.250000 | 54.000000 | 282.720001 | 1472.399994 | 0.031410 | 0.008706 |
291 | 2020-09-29 | 20.850000 | 27.100000 | 18.780001 | 54.639999 | 286.239990 | 1530.299999 | 0.039324 | 0.012450 |
292 | 2020-09-30 | 21.219999 | 25.280001 | 20.100000 | 54.959999 | 289.260010 | 1534.599987 | 0.002810 | 0.010551 |
293 | 2020-10-01 | 21.760000 | 25.080000 | 20.950001 | 55.084999 | 289.679993 | 1545.414989 | 0.007047 | 0.001452 |
294 | 2020-10-02 | 21.180000 | 23.620001 | 20.900000 | 54.889999 | 287.829987 | 1526.149994 | -0.012466 | -0.006386 |
299 | 2020-10-09 | 21.469999 | 26.770000 | 18.110001 | 56.195000 | 295.140015 | 1555.564999 | 0.019274 | 0.025397 |
304 | 2020-10-16 | 28.480000 | 22.809999 | 19.200001 | 56.825001 | 300.700012 | 1586.635014 | 0.019973 | 0.018839 |
309 | 2020-10-23 | 27.160000 | 20.340000 | 24.670000 | 55.650002 | 293.459991 | 1580.390030 | -0.003936 | -0.024077 |
314 | 2020-10-30 | 30.580000 | 15.380000 | 24.040001 | 53.514999 | 281.989990 | 1515.624996 | -0.040980 | -0.039085 |
319 | 2020-11-06 | 41.630001 | 17.290001 | 27.080000 | 56.505001 | 297.250000 | 1678.335033 | 0.107355 | 0.054115 |
324 | 2020-11-13 | 44.560001 | 19.219999 | 29.180000 | 57.970001 | 303.440002 | 1755.990028 | 0.046269 | 0.020824 |
329 | 2020-11-20 | 49.250000 | 25.780001 | 40.330002 | 58.529999 | 304.190002 | 1936.449997 | 0.102768 | 0.002472 |
333 | 2020-11-27 | 54.000000 | 27.180000 | 38.770000 | 59.209999 | 306.730011 | 1976.589989 | 0.020729 | 0.008350 |
338 | 2020-12-04 | 43.040001 | 22.070000 | 35.680000 | 59.154999 | 306.720001 | 1844.184982 | -0.066987 | -0.000033 |
343 | 2020-12-11 | 41.980000 | 21.780001 | 33.259998 | 58.730000 | 303.399994 | 1808.069981 | -0.019583 | -0.010824 |
348 | 2020-12-18 | 46.720001 | 21.150000 | 38.700001 | 59.285000 | 305.079987 | 1885.535007 | 0.042844 | 0.005537 |
357 | 2021-01-04 | 53.490002 | 21.420000 | 34.750000 | 59.305000 | 304.350006 | 1897.095016 | 0.006131 | -0.002393 |
358 | 2021-01-05 | 53.200001 | 22.430000 | 35.900002 | 59.419998 | 305.070007 | 1914.819984 | 0.009343 | 0.002366 |
359 | 2021-01-06 | 50.500000 | 23.650000 | 37.889999 | 60.270000 | 309.769989 | 1940.450001 | 0.013385 | 0.015406 |
360 | 2021-01-07 | 54.279999 | 27.600000 | 39.430000 | 60.799999 | 312.799988 | 2017.119984 | 0.039511 | 0.009781 |
361 | 2021-01-08 | 58.919998 | 25.565001 | 38.310001 | 61.099998 | 314.010010 | 2025.419975 | 0.004115 | 0.003868 |
366 | 2021-01-15 | 56.270000 | 23.340000 | 38.130001 | 61.259998 | 315.200012 | 1993.319981 | -0.015849 | 0.003790 |
367 | 2021-01-19 | 58.439999 | 23.760000 | 37.730000 | 61.270000 | 315.200012 | 2006.689999 | 0.006707 | 0.000000 |
from plotly.subplots import make_subplots
import plotly.graph_objects as go
import plotly.express as px
import dash # (version 1.12.0) pip install dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import datetime
# app = dash.Dash(__name__)
fig = make_subplots(
rows=1, cols=2,
specs=[[{"type": "xy"}, {"type": "domain"}]])
fig.add_trace(go.Bar(y=total_portfolio, x=stock_names_and_total, name='', showlegend=False,
text = total_portfolio_str, textposition='outside'),
row=1, col=1)
fig.update_yaxes(range=[0,sum(total)+500], row=1, col=1)
fig.add_trace(go.Pie(values=total, labels=stock_names, hole=.3, showlegend=True,
text=total_str, name='Stock', titleposition='middle center',
customdata=shares,
hovertemplate = "%{label}: <br>Size: %{percent} </br> %{text} </br> Shares: %{customdata}",
textfont=dict(
#family="sans serif",
size=14,
#color="LightSeaGreen"
)
),
row=1, col=2)
fig.update_layout(title_text='PORTFOLIO OVERVIEW', showlegend=True)
fig.show()
fig2 = make_subplots(
rows=1, cols=2,
specs=[[{"type": "xy"}, {"type": "xy"}]])
fig2.add_trace(go.Scatter(x=stocks_close_dropna["Date"],
y=stocks_close_dropna['Portfolio Return'],
name='Portfolio Return'), row=1, col=1)
fig2.add_trace(go.Scatter(x=stocks_close_dropna["Date"],
y=stocks_close_dropna['Market Return'],
name='Market Return'), row=1, col=1)
fig2.add_trace(go.Bar(name='Initial Investment', x=myportfolio['Stocks'],
y=myportfolio['Initial Purchase per Stock'],
text=initial_purchase_str, textposition='outside',
showlegend=True), row=1, col=2) #marker_color='midnightblue')
fig2.add_trace(go.Bar(name='Current Value', x=myportfolio['Stocks'],
y=myportfolio['Current Value'],
text=['$'+str(round(i)) for i in total_portfolio], textposition='outside',
showlegend=True), row=1, col=2) #marker_color=' darkred')
fig2.update_yaxes(range=[0,max(total)+100], row=1, col=2)
fig2.update_layout(height=500, title_text='PORTFOLIO vs MARKET (S&P 500) RETURNS', showlegend=True)
fig2.show()
app.layout = html.Div(children=[
html.H1(children='My Portfolio Dash Visualization'),
html.Div(children='''
Dash: A web application framework for Python.
'''),
dcc.Graph(
id='example-graph',
figure=fig
),
dcc.Graph(
id='example-graph2',
figure=fig2
)
])
if __name__ == '__main__':
app.run_server(debug=True, use_reloader=False)
Dash is running on http://127.0.0.1:8050/ Dash is running on http://127.0.0.1:8050/ Dash is running on http://127.0.0.1:8050/ Dash is running on http://127.0.0.1:8050/ Dash is running on http://127.0.0.1:8050/ Dash is running on http://127.0.0.1:8050/ Dash is running on http://127.0.0.1:8050/ Dash is running on http://127.0.0.1:8050/ * Serving Flask app "__main__" (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: on
import plotly.express as px
fig = px.line(stocks_close_dropna, x="Date", y=['Portfolio Return', 'Market Return'],
title='Portfolio vs Market(S&P 500)')
fig.update_xaxes(
rangeslider_visible=True,
rangeselector=dict(
buttons=list([
dict(count=1, label="1m", step="month", stepmode="backward"),
dict(count=6, label="6m", step="month", stepmode="backward"),
dict(count=1, label="YTD", step="year", stepmode="todate"),
dict(count=1, label="1y", step="year", stepmode="backward"),
dict(step="all")
])
)
)
fig.show()
import plotly.graph_objects as go
fig = go.Figure(data=[
go.Bar(name='Initial Investment', x=myportfolio['Stocks'],
y=myportfolio['Initial Purchase per Stock']), #marker_color='midnightblue'),
go.Bar(name='Current Value', x=myportfolio['Stocks'],
y=myportfolio['Current Value']) #marker_color=' darkred')
])
# Change the bar mode
fig.update_layout(title='Portfolio Evolution', barmode='group')
fig.show()